package ch.il07.converter.persistence;

import java.util.List;

import ch.il07.converter.persistence.entities.AccessLevel;
import ch.il07.converter.persistence.entities.Measurand;
import ch.il07.converter.persistence.entities.Unit;
import ch.il07.converter.persistence.entities.User;
import ch.il07.converter.persistence.exceptions.AlreadyDefinedException;
import ch.il07.converter.persistence.exceptions.NoSuchMeasurandException;
import ch.il07.converter.persistence.exceptions.NoSuchUnitException;
import ch.il07.converter.persistence.exceptions.NoSuchUserException;
import ch.il07.converter.persistence.exceptions.PersistenceException;
import ch.il07.converter.persistence.exceptions.UpdateException;
import ch.il07.converter.persistence.exceptions.UserAlreadyExistsException;

/**
 * 
 * @author Reto Hablützel
 * 
 * @desc interface to access persistance layer
 * 
 */
public interface Persistence {

	/**
	 * 
	 * @return all public Measurands
	 * 
	 * @throws PersistenceException
	 *             if a database error occurs
	 * 
	 * @see Measurand
	 */
	List<Measurand> getMeasurands() throws PersistenceException;

	/**
	 * 
	 * @param username
	 *            to identify (must exist!)
	 * 
	 * @return all private measurands to this user
	 * 
	 * @throws PersistenceException
	 *             if a database error occurs
	 * 
	 * @see Measurand
	 */
	List<Measurand> getMeasurands(String username) throws NoSuchUserException, PersistenceException;

	/**
	 * 
	 * @param measurandName
	 * @param username
	 *            to identify (must exist!)
	 * 
	 * @return instance of measurand. null if no such measurand
	 * 
	 * @throws PersistenceException
	 *             if a database error occurs
	 * 
	 * @see Measurand
	 */
	Measurand getMeasurand(String measurandName, String username)
			throws NoSuchUserException, PersistenceException;

	/**
	 * 
	 * @param username
	 * @param password
	 * 
	 * @return an instance of the specified user. null if there's no user with
	 *         this username and password
	 * @throws PersistenceException
	 *             if a database error occurs
	 * 
	 * @see User
	 */
	User getUser(String username, String password) throws PersistenceException;
	
	/**
	 * 
	 * @param username
	 * @return user object (without password), null if no such user
	 * @throws PersistenceException on db error
	 */
	User getUser(String username) throws PersistenceException;

	/**
	 * 
	 * @param measurand
	 * @param username
	 *            to identify (must exist!)
	 * 
	 * @throws AlreadyDefinedException
	 *             if the measurand already exists
	 * @throws PersistenceException
	 *             if a database error occurs
	 * @throws IllegalArgumentException
	 * 				if the defaultUnit is null
	 * @throws IllegalArgumentException
	 * 				if the defaultUnit does not have 0 as divisor value
	 */
	void addMeasurand(Measurand measurand, String username)
			throws NoSuchUserException, AlreadyDefinedException, PersistenceException;

	/**
	 * 
	 * @param measurand
	 *            of the unit
	 * @param unit
	 *            to add
	 * 
	 * @throws AlreadyDefinedException
	 *             if the unit already exists
	 * @throws PersistenceException
	 *             if a database error occurs
	 * @throws IllegalArgumentException
	 * 				if no owner is assigned to the measurand
	 */
	void addUnit(Measurand measurand, Unit unit)
			throws AlreadyDefinedException, PersistenceException;

	/**
	 * 
	 * @param username
	 * @param email
	 * @param password
	 * @param accessLevel
	 * 
	 * @throws UserAlreadyExistsException
	 *             if the user already exists
	 * @throws PersistenceException
	 *             if a database error occurs
	 */
	void addUser(String username, String email, String password,
			AccessLevel accessLevel) throws UserAlreadyExistsException,
			PersistenceException;

	/**
	 * 
	 * @param measurand
	 *            to update
	 * 
	 * @throws PersistenceException
	 *             if a database error occurs
	 * @throws UpdateException
	 *             on update error (e.g. object doesn't exist)
	 */
	void updateMeasurand(Measurand measurand)
			throws NoSuchUserException, PersistenceException;

	/**
	 * 
	 * @param measurand
	 *            to which the unit belongs
	 * @param unit
	 *            to update
	 * 
	 * @throws PersistenceException
	 *             if a database error occurs
	 * @throws UpdateException
	 *             on update error (e.g. object doesn't exist)
	 */
	void updateUnit(Measurand measurand, Unit unit) throws PersistenceException;

	/**
	 * 
	 * @param user
	 *            to update
	 * @throws PersistenceException
	 *             if a database error occurs
	 * @throws UpdateException
	 *             on update error (e.g. object doesn't exist)
	 */
	void updateUser(User user) throws PersistenceException;

	/**
	 * @desc nominates the measurand for this user
	 * 
	 * @param user
	 * @param measurand
	 * 
	 * @throws PersistenceException
	 *             on database error
	 */
	void nominate(User user, Measurand measurand) throws PersistenceException;

	/**
	 * 
	 * @desc nominates the unit to the specific measurand for this user
	 * 
	 * @param user
	 * @param measurand
	 * @param unit
	 * 
	 * @throws PersistenceException
	 *             on database error
	 */
	void nominate(User user, Measurand measurand, Unit unit)
			throws PersistenceException;

	/**
	 * 
	 * @param measurand
	 *            to delete
	 * @param username
	 *            to identify (must exist!)
	 * 
	 * @throws PersistenceException
	 *             if a database error occurs
	 */
	void deleteMeasurand(Measurand measurand, String username)
			throws NoSuchUserException, PersistenceException;

	/**
	 * 
	 * @param measurand
	 *            to the unit
	 * @param unit
	 *            to delete
	 * 
	 * @throws NoSuchUnitException
	 *             if the unit doesn't exist
	 * @throws NoSuchMeasurandException
	 *             if the measurand doesn't exist
	 * @throws PersistenceException
	 *             if a database error occurs
	 */
	void deleteUnit(Measurand measurand, Unit unit) throws NoSuchUnitException,
			NoSuchMeasurandException, PersistenceException;

	/**
	 * 
	 * @param user
	 * 
	 * @throws PersistenceException
	 *             if a database error occurs
	 */
	void deleteUser(User user) throws PersistenceException;
	
	/**
	 * 
	 * @return List with all Measurands that have been nominated by users
	 * 
	 * @throws PersistenceException
	 * 				if a database error occurs or sth similar
	 */
	List<Measurand> getAllNominatedMeasurands() throws PersistenceException;
	
	/**
	 * 
	 * @param Measurand measurand for which the units are to be loaded
	 * 
	 * @return List with all Units for the giben measurand
	 * 
	 * @throws NoSuchMeasurandException
	 * 					if there's no such measurand
	 * @throws PersistenceException
	 * 					if a database error occurs or sth similar
	 */
	List<Unit> getAllNominatedUnits() throws NoSuchMeasurandException, PersistenceException;
}